package com.ouroboroswiki.core.content.markup.processor;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import com.ouroboroswiki.core.Content;
import com.ouroboroswiki.core.ContentException;
import com.ouroboroswiki.core.ContentPath;
import com.ouroboroswiki.core.ContentRepository;
import com.ouroboroswiki.core.ContentUtil;
import com.ouroboroswiki.core.ContentValidationResult;
import com.ouroboroswiki.core.MultipartVersion;
import com.ouroboroswiki.core.Version;

public class LoadContentMarkupHandler extends AbstractExternalContentMarkupHandler implements MarkupHandler {
	
	private static final Logger log = Logger.getLogger(LoadContentMarkupHandler.class.getName());
	
	
	public static final String ELEMENT_VERSION 	= "version";
	
	private ContentRepository source;
	
	private DocumentBuilderFactory documentBuilderFactory;
	
	
	public LoadContentMarkupHandler( DocumentBuilderFactory documentBuilderFactory ) {
		this.documentBuilderFactory = documentBuilderFactory;
	}
	
	public void setSource( ContentRepository source ) {
		this.source = source;
	}

	@Override
	public List<Node> replace(Object principal, Element e, Document parent, Map<String, Content> childContents, ContentPath path, Version version, Collection<ContentValidationResult> validations, Map<String, Object> properties) 
		throws IOException {
		String id = e.getAttribute(ATTRIBUTE_ID);
		// load the content
		ContentPath childPath = buildPathFromContext(e, path);
		// load the version from the file if it exists
		Version childVersion;
		if( id != null && id.length() > 0 ) {
			if( version instanceof MultipartVersion ) {
				MultipartVersion multipartVersion = (MultipartVersion)version;
				childVersion = multipartVersion.getVersions().get(id);
			} else {
				childVersion = null;
			}
		} else {
			childVersion = null;
		}
		try {
			Content childContent = source.getContent(principal, childPath, childVersion, properties);
			if( id != null && id.length() > 0 ) {
				childContents.put( id, childContent );
			}
			InputStream ins = ContentUtil.openInputStream(childContent);
			try {
				// read into a document? 
				//TODO what if it's just an XML fragment?
				DocumentBuilder documentBuilder;
				try {
					documentBuilder = documentBuilderFactory.newDocumentBuilder();
					Document subDocument;
					try {
						subDocument = documentBuilder.parse(ins);
						Element childElement = (Element)parent.importNode(subDocument.getDocumentElement(), true);
						return Arrays.asList((Node)childElement);
					} catch( SAXException ex ) {
						validations.add(new ContentValidationResult(ContentValidationResult.Level.Error, "unable to parse child content "+id, ex));
					}
				} catch( ParserConfigurationException ex ) {
					validations.add(new ContentValidationResult(ContentValidationResult.Level.Error, "unable to create document builder "+documentBuilderFactory, ex));
					log.log(Level.WARNING, "unable to create document builder "+documentBuilderFactory, ex);
				}
			} finally {
				try {
					ins.close();
				} catch( Exception ex ) {
					log.log( Level.WARNING, "unable to close "+childContent, ex );
				}
			}
		} catch( ContentException ex ) {
			validations.add(new ContentValidationResult(ContentValidationResult.Level.Error, "unable to load child content "+id, ex));
			log.log(Level.WARNING, "unable to load child content "+id, ex);
		}
		return null;
	}

}
